package com.hbpa.pan.schedule;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.hbpa.pan.core.exception.RPanFrameworkException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;

/**
 * @author: BlcakTiger
 * @date: 2023/10/19 21:10
 * @contact: hsf6661@163.com
 * @description: 定时任务管理器
 */
@Component
@Slf4j
public class ScheduleManager {

    /**
     * 注入定时任务调度器
     */
    @Resource
    private ThreadPoolTaskScheduler taskScheduler;

    /**
     * 用作定时任务的缓存
     */
    private final Map<String,ScheduleTaskHolder> cache = new ConcurrentHashMap<>();

    /**
     * 将一个定时任务添加到{@ThreadPoolTaskScheduler} 定时调度器线程池,并将定时任务和其返回结果缓存
     * @param scheduleTask 定时任务实现类
     * @param cron 定时任务的cron表达式 一种描述定时任务执行时间的字符串表示法
     * @return 缓存的key值
     */
    public String startTask(ScheduleTask scheduleTask,String cron){
        //在指定的延迟时间后执行任务
        ScheduledFuture<?> scheduledFuture = taskScheduler.schedule(scheduleTask, new CronTrigger(cron));
        String key = UUID.randomUUID().toString();
        ScheduleTaskHolder scheduleTaskHolder = new ScheduleTaskHolder(scheduleTask, scheduledFuture);
        cache.put(key,scheduleTaskHolder);
        log.info("{}启动成功,唯一标识为{}",scheduleTask.getTaskName(),key);
        return key;
    }

    /**
     * 根据key值从缓存中获取定时任务并将其停止
     * @param key {@ScheduleTask} 在缓存中的key值
     */
    public void stopTask(String key){
        if (StrUtil.isBlank(key)){
            return;
        }
        //从缓存中获取key值
        ScheduleTaskHolder scheduleTaskHolder = cache.get(key);
        if (ObjectUtil.isNull(scheduleTaskHolder)){
            return;
        }
        //从封装中获取定时任务的future
        ScheduledFuture scheduledFuture = scheduleTaskHolder.getScheduledFuture();
        //取消任务
        boolean cancel = scheduledFuture.cancel(true);
        if (cancel){
            log.info("{}停止成功，唯一标识为：",scheduleTaskHolder.getScheduleTask().getTaskName());
        }else {
            log.info("{}停止失败，唯一标识为：",scheduleTaskHolder.getScheduleTask().getTaskName());
        }
    }

    /**
     * 变更指定定时任务的执行时间
     * @param key {@ScheduleTask} 在缓存中对应的键值
     * @param cron 新的定时任务的cron表达式 (一种描述定时任务执行时间的字符串表示法)
     * @return 变更后的新的定时任务的唯一标识
     */
    public String changeTask(String key,String cron){
        if (StringUtils.isAnyBlank(key,cron)){
            throw  new RPanFrameworkException("定时任务的唯一标识或新的定时执行表达式不为为空!");
        }
        ScheduleTaskHolder scheduleTaskHolder = cache.remove(key);
        log.info("{}已从缓存中移除成功",scheduleTaskHolder.getScheduleTask().getTaskName());
        if (ObjectUtil.isNull(scheduleTaskHolder)){
            throw new RPanFrameworkException("唯一标识不存在!");
        }
        stopTask(key);
        log.info("{}已停止成功，正在生成新的定时任务",scheduleTaskHolder.getScheduleTask().getTaskName());
        return startTask(scheduleTaskHolder.getScheduleTask(),cron);
    }
}
